#include<iostream>
#include<string>
#include<strings.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include<arpa/inet.h>
//using namespace std;

void Usage(const char *str)
{
    printf("\nUsage: %s server_ip server_port\n\n", str);
}

// ./udpclient server_ip server_port
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(0);
    }
    std::string server_ip = argv[1];
    uint16_t server_port = std::stoi(argv[2]);//

    struct sockaddr_in server;
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(server_ip.c_str());//1. string -> uint32_t 2. uint32_t必须是网络序列的 
    socklen_t len = sizeof(server);

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        std::cout << "socket error" << std::endl;
        return 1;
    }

    //client的bind操作：
    // client 也需要 bind !!! --- 只不过不需要用户显式的 bind !!! 一般由OS随机选择
    //一个端口号只能被一个进程bind，对于server和client都是如此
    //client的port是多少不重要，只要能保证主机上的唯一性即可
    //系统在client首次发送数据的时候进行bind

    std::string message;
    char buffer[1024];
    while(true)
    {
        //1.接收user数据
        std::cout << "Please Enter@";
        std::getline(std::cin, message);
        //2.发送数据
        sendto(sockfd, message.c_str(), message.size(), 0, (const sockaddr *)&server, len);

        struct sockaddr_in tmp;
        socklen_t length = sizeof(tmp);
        ssize_t n = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr *)&tmp, &length);
        if(n > 0)
        {
            buffer[n] = 0;
            std::cout << buffer << std::endl;
        }
    }
    
    close(sockfd);
    return 0;
}